﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenSSL.X509;
using OpenSSL.Core;
using OpenSSL.Crypto;
using Sicurezza.Entita;
using System.IO;

namespace Sicurezza.Client.Manager
{
    public class SSLManager
    {
        private static X509Certificate cacert;

        static SSLManager()
        {
            string cert = FileManager.LoadCaCert();
            cacert = new X509Certificate(new BIO(cert));
        }

        public static bool CheckSign(Sicurezza.Client.Manager.CA.SignedMessage sm)
        {
            return CheckSign(sm, cacert);
        }

        private static bool CheckSign(Sicurezza.Client.Manager.CA.SignedMessage sm, X509Certificate cert)
        {
            if (sm.Signature == null)
                return true;

            MessageDigestContext mdc = new MessageDigestContext(MessageDigest.SHA1);

            try
            {
                return mdc.Verify(ASCIIEncoding.ASCII.GetBytes(sm.Message), sm.Signature, cert.PublicKey);
            }
            catch (OpenSslException ex)
            {
                throw new ManagerException("Message signature is corrupted or invalid.");
            }
        }

        internal static void Save(X509Certificate c)
        {
            throw new NotImplementedException();
        }

        public static byte[] Sign(string message, X509Certificate Certificato, string password)
        {
            string key = FileManager.LoadPrivateKey(Certificato.SerialNumber);
            CryptoKey k = null;
            try
            {
                k = CryptoKey.FromPrivateKey(new BIO(key), password);
            }
            catch (OpenSslException ex) 
            {
                throw new ManagerException("Incorrect password. Try again");
            }

            return Sign(message, k);

        }
        public static byte[] Sign(string message, CryptoKey key)
        {

            MessageDigestContext mdc = new MessageDigestContext(MessageDigest.SHA1);
            return mdc.Sign(ASCIIEncoding.ASCII.GetBytes(message), key);

        }


        public static List<EncryptedFile> Encipher(List<string> files, MailMessage mm)
        {
            CipherContext cc = new CipherContext(Cipher.CreateByName(mm.Cipher));
            List<EncryptedFile> encFiles = new List<EncryptedFile>();
            EncryptedFile ef = null;
            for (int i = 0; i < files.Count; i++)
            {
                ef = new EncryptedFile();
                ef.Name = new FileInfo(files[i]).Name;
                byte[] file = FileManager.GetFile(files[i]);
                ef.File = cc.Encrypt(file, mm.EncipheredKey, mm.IV);
                encFiles.Add(ef);
            }

            return encFiles;
        }

        public static byte[] Encipher(byte[] key, CryptoKey cryptoKey)
        {
            RSA Rsakey = cryptoKey.GetRSA();
            return Rsakey.PublicEncrypt(key, RSA.Padding.PKCS1);
        }

        public static byte[] Decipher(byte[] key, CryptoKey cryptoKey)
        {
            RSA Rsakey = cryptoKey.GetRSA();
            return Rsakey.PrivateDecrypt(key, RSA.Padding.PKCS1);
        }


        public static List<byte[]> Decipher(MailMessage mm, X509Certificate recipient, string password)
        {
            if (mm.EncipheredKey == null)
                return mm.Files.Select(a=> a.File).ToList();

            CryptoKey privateKey = KeyManager.Load(recipient.SerialNumber, password);

            List<byte[]> files = new List<byte[]>();
            mm.EncipheredKey = Decipher(mm.EncipheredKey, privateKey);

            CipherContext cc = new CipherContext(Cipher.CreateByName(mm.Cipher));
            for (int i = 0; i < mm.Files.Count; i++)
            {
                files.Add(cc.Decrypt(mm.Files[i].File, mm.EncipheredKey, mm.IV));
            }

            return files;

        }

        public static bool CheckSign(SignedMessage sm)
        {
            return CheckSign(new Sicurezza.Client.Manager.CA.SignedMessage() { Message = sm.Message, Signature = sm.Signature });
        }

        public static bool CheckSign(SignedMessage sm, X509Certificate senderCertificate)
        {
            return CheckSign(new Sicurezza.Client.Manager.CA.SignedMessage() { Message = sm.Message, Signature = sm.Signature },
                             senderCertificate);
        }
    }
}
